﻿using System;
using System.Threading;
using CommandRunner.Contract;
using CommandRunner.Core;
using CommandRunner.Model;
using CommandRunner.WCFDataTransport;
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;

namespace CommandRunner.MSBuildTask
{
    public class ExecuteRemoteCommand : Task
    {
        [Required]
        public string Server { get; set; }

        public string Port { get; set; }

        [Required]
        public string Command { get; set; }

        public string WorkingDirectory { get; set; }

        public string InteractiveWindow { get; set; }

        public string MonitorSuccess { get; set; }

        public int? PortNumber
        {
            get
            {
                int portNumber;
                if (int.TryParse(Port, out portNumber))
                    return portNumber;
                else
                    return null;
            }
        }

        public bool IsInteractive
        {
            get
            {
                if (String.IsNullOrEmpty(InteractiveWindow))
                    return false;

                switch (InteractiveWindow.ToUpper())
                {
                    case "TRUE":
                    case "OK":
                    case "YES":
                        return true;
                    default:
                        return false;
                }
            }
        }

        public bool ShouldMonitor
        {
            get
            {
                if (String.IsNullOrEmpty(MonitorSuccess))
                    return true;

                switch (MonitorSuccess.ToUpper())
                {
                    case "TRUE":
                    case "OK":
                    case "YES":
                        return true;
                    default:
                        return false;
                }
            }
        }

        private bool _resultReturned = false;

        public override bool Execute()
        {
            try
            {
                base.Log.LogMessageFromText(String.Format("Executing command \"{0}\" on {1} in \"{2}\"", Command, Server, WorkingDirectory), MessageImportance.Normal);

                Runner runner = SetupSingleCommandRunner(Command, Server, PortNumber, WorkingDirectory, IsInteractive, ShouldMonitor);
                runner.CommandCompleted += HandleCommandCompleted;
                runner.CommandFailed += HandleCommandFailed;

                CommandExecutionStatus status = runner.RunCommands();

                DateTime start = DateTime.UtcNow;
                while (!_resultReturned)
                {
                    Thread.Sleep(1000);
                    if ((DateTime.UtcNow - start) > TimeSpan.FromMinutes(5))
                        throw new TimeoutException("The timeout for waiting on Command Runner events to fire has expired");
                }

                return (status == CommandExecutionStatus.Success);
            }
            catch (Exception e)
            {
                base.Log.LogErrorFromException(e, true);
                return false;
            }
        }

        public void HandleCommandCompleted(CommandResult result)
        {
            base.Log.LogMessageFromText(result.Output, MessageImportance.Normal);
            _resultReturned = true;
        }

        public void HandleCommandFailed(CommandResult result)
        {
            base.Log.LogError(result.Output);
            _resultReturned = true;
        }

        private static Runner SetupSingleCommandRunner(string command, string server, Nullable<int> port, string workingDirectory, bool interactive, bool monitorSuccess)
        {
            ICommandRunnerConfigurationManager configManager = new ConfigurationManagerSingleCommand(command, server, port, workingDirectory, interactive, monitorSuccess);
            ICommandRunnerClientDataTransport dataTransport = new CommandRunnerClient();
            Runner commandRunner = new Runner(configManager, dataTransport);
            return commandRunner;
        }
    }
}
